package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.BusinessInnerMsgTemplate;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.context.StaticContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.database.mybatis.typehandler.TypeHandlerUtil;
import com.eastfair.home.dto.BuilderRepairReportDTO;
import com.eastfair.home.enumeration.BuilderRepairReportRepairStatusEnum;
import com.eastfair.messagecenter.util.SendMsgUtil;
import com.eastfair.projectcore.enumeration.MenuAffiliationEnum;
import com.eastfair.venueservice.dao.RepairReportMapper;
import com.eastfair.venueservice.dto.RepairReportDTO;
import com.eastfair.venueservice.entity.CreatCode;
import com.eastfair.venueservice.entity.RepairReport;
import com.eastfair.venueservice.enumeration.RepairReportRepairStatusEnum;
import com.eastfair.venueservice.enumeration.RepairReportRepairTypeEnum;
import com.eastfair.venueservice.enumeration.ServiceOrderWorkOrderStatusEnum;
import com.eastfair.venueservice.enumeration.WorkOrderWorkOrderStatusEnum;
import com.eastfair.venueservice.exceptioncode.VenueServiceExceptionCode;
import com.eastfair.venueservice.service.RepairReportService;
import com.eastfair.venueservice.service.VenueManageBuilderRepairReportService;
import com.eastfair.venueservice.vo.RepairReportVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 报修申请
 * </p>
 *
 * @author dqq
 * @date 2022-11-21
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class RepairReportServiceImpl extends SuperServiceImpl<RepairReportMapper, RepairReport> implements RepairReportService {

    private static final String REPAIR_REPORT_NUMBER_FIELD = "repair_report_number";

    private static final int REPAIR_REPORT_NUMBER_LENGTH = 5;

    @Resource
    private RepairReportMapper repairReportMapper;

    @Resource
    private VenueManageBuilderRepairReportService venueManageBuilderRepairReportService;

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private SendMsgUtil sendMsgUtil;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<RepairReport> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(RepairReport model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (model.getRepairStatus() == null) {
            model.setRepairStatus(RepairReportRepairStatusEnum.HAS_REPORT);
        }
        if (model.getReportTime() == null) {
            model.setReportTime(LocalDateTime.now());
        }
        if (model.getIsBookService() == null) {
            model.setIsBookService(0);
        }
        return R.successDef();
    }

    @Override
    public Page<RepairReportVO> listRepairReportVO(PageParams<RepairReportDTO> pageParams) {
        log.info("listRepairReportVO - 查询报修申请列表VO, pageParams={}", pageParams);
        Page<RepairReport> pageParam = pageParams.buildPage();
        QueryWrapper<RepairReport> queryWrapper = createRepairReportQueryWrapper(pageParams.getModel());
        Page<RepairReport> page = page(pageParam, queryWrapper);
        Page<RepairReportVO> voPage = new Page<>();
        BeanUtil.copyProperties(page, voPage);
        List<RepairReport> list = page.getRecords();
        if (list == null || list.isEmpty()) {
            return voPage;
        }
        List<RepairReportVO> voList = list
                .stream()
                .map(repairReport -> BeanUtil.toBean(repairReport, RepairReportVO.class))
                .collect(Collectors.toList());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public Page<RepairReportVO> listRepairReportVOForVenue(PageParams<RepairReportDTO> pageParams) {
        log.info("listRepairReportVOForVenue - 场馆查询报修申请, pageParams={}", pageParams);
        Page<RepairReport> pageParam = pageParams.buildPage();
        RepairReportDTO model = pageParams.getModel();
        QueryWrapper<RepairReport> queryWrapper = createRepairReportVOQueryWrapperForVenue(model);
        Page<RepairReportVO> voPage = repairReportMapper.listRepairReportVOForVenue(pageParam, queryWrapper);
        List<RepairReportVO> voList = voPage.getRecords();
        if (voList == null || voList.isEmpty()) {
            return voPage;
        }
        for (RepairReportVO repairReportVO: voList) {
            String phone = repairReportVO.getPhone();
            String decryptPhone = TypeHandlerUtil.decrypt(phone);
            repairReportVO.setPhone(decryptPhone);
        }
        return voPage;
    }

    @Override
    public List<RepairReport> listRepairReport(RepairReportDTO repairReportDTO) {
        QueryWrapper<RepairReport> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(RepairReport::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(StrUtil.isNotBlank(repairReportDTO.getRepairReportNumber()),
                        RepairReport::getRepairReportNumber, repairReportDTO.getRepairReportNumber())
        ;
        return list(queryWrapper);
    }

    @Override
    public RepairReport getByReportRepairNumber(String repairReportNumber) {
        RepairReportDTO repairReportDTO = new RepairReportDTO();
        repairReportDTO.setRepairReportNumber(repairReportNumber);
        List<RepairReport> list = listRepairReport(repairReportDTO);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public RepairReportVO getVOByReportRepairNumber(String repairReportNumber) {
        log.info("getVOByReportRepairNumber - 报修单号获取报修申请VO, repairReportNumber={}", repairReportNumber);
        RepairReport repairReport = getByReportRepairNumber(repairReportNumber);
        if (repairReport == null) {
            return null;
        }
        return BeanUtil.toBean(repairReport, RepairReportVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RepairReport saveRepairReport(RepairReportDTO repairReportDTO) {
        log.info("saveRepairReport - 保存报修申请, repairReportDTO={}", repairReportDTO);
        // 生成报修单号
        if (StrUtil.isBlank(repairReportDTO.getRepairReportNumber())) {
            String prefix = LocalDateTimeUtil.format(LocalDate.now(), "yyyyMMdd");
            String repairReportNumber = CreatCode.creatCode(baseMapper, REPAIR_REPORT_NUMBER_FIELD, REPAIR_REPORT_NUMBER_LENGTH, prefix);
            repairReportDTO.setRepairReportNumber(repairReportNumber);
        }
        // 保存报修申请
        RepairReport repairReport = BeanUtil.toBean(repairReportDTO, RepairReport.class);
        save(repairReport);
        // 发送报修申请消息
        asyncSendReportInnerMsg(repairReport);
        return repairReport;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RepairReport updateRepairReport(RepairReportDTO repairReportDTO) {
        log.info("updateRepairReport - 更新报修申请, repairReportDTO={}", repairReportDTO);
        RepairReport repairReport = BeanUtil.toBean(repairReportDTO, RepairReport.class);
        updateById(repairReport);
        return repairReport;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelRepairReport(String repairReportNumber) {
        log.info("cancelRepairReport - 取消报馆申请, repairReportNumber={}", repairReportNumber);
        RepairReport repairReport = getByReportRepairNumber(repairReportNumber);
        if (repairReport == null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_NOT_EXIST);
        }
        if (RepairReportRepairStatusEnum.HAS_DISPATCH.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_CAN_NOT_CANCEL.getCode(), "取消报修申请失败, 报修工单已派单");
        }
        if (RepairReportRepairStatusEnum.COMPLETE.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_CAN_NOT_CANCEL.getCode(), "取消报修申请失败, 报修工单已完成");
        }
        if (repairReport.getIsBookService() == BusinessConstant.YES) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_CAN_NOT_CANCEL.getCode(), "取消报修申请失败, 报修已预定服务");
        }
        if (RepairReportRepairStatusEnum.FINISH.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_CAN_NOT_CANCEL.getCode(), "取消报修申请失败, 报修申请已结束");
        }
        repairReport.setRepairStatus(RepairReportRepairStatusEnum.CANCEL);
        return updateById(repairReport);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateHasDispatch(String repairReportNumber) {
        log.info("updateHasDispatch - 更新报修申请状态为已完成, repairReportNumber={}", repairReportNumber);
        RepairReport repairReport = getByReportRepairNumber(repairReportNumber);
        if (repairReport == null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_NOT_EXIST);
        }
        if (RepairReportRepairStatusEnum.CANCEL.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_HAS_CANCEL.getCode(), "报修申请已取消，不可派单");
        }
        if(RepairReportRepairStatusEnum.HAS_DISPATCH.eq(repairReport.getRepairStatus())) {
            return true;
        }
        // 更新综合服务报修申请为已派单
        repairReport.setWorkOrderStatus(WorkOrderWorkOrderStatusEnum.ORDER_TO_BE_RECEIVED.getCode());
        repairReport.setRepairStatus(RepairReportRepairStatusEnum.HAS_DISPATCH);
        repairReport.setDispatchWorkOrderTime(LocalDateTime.now());
        updateById(repairReport);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateFinish(RepairReportDTO repairReportDTO) {
        log.info("updateComplete - 更新报修申请为已完成, repairReportDTO={}", repairReportDTO);
        RepairReport repairReport = getByReportRepairNumber(repairReportDTO.getRepairReportNumber());
        if (repairReport == null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_NOT_EXIST);
        }
        if (RepairReportRepairStatusEnum.CANCEL.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_HAS_CANCEL.getCode(), "报修申请已取消，不可完结报修");
        }
        if(RepairReportRepairStatusEnum.FINISH.eq(repairReport.getRepairStatus())) {
            return true;
        }
        if (!RepairReportRepairStatusEnum.COMPLETE.eq(repairReport.getRepairStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_CAN_NOT_FINISH.getCode(), "报修工单未完成，不可完结");
        }
        repairReport.setRepairStatus(RepairReportRepairStatusEnum.FINISH);
        repairReport.setCompleteRemark(repairReportDTO.getCompleteRemark());
        updateById(repairReport);
        // 更新搭建商报修申请为已完结
        if (MenuAffiliationEnum.P_COMPOSITE_PRODUCER.getCode().equals(repairReport.getBelongSystem())
                && RepairReportRepairTypeEnum.HOME_REPAIR.eq(repairReport.getRepairType())) {
            BuilderRepairReportDTO builderRepairReportDTO = new BuilderRepairReportDTO();
            builderRepairReportDTO.setRepairReportNumber(repairReportDTO.getRepairReportNumber());
            builderRepairReportDTO.setCompleteRemark(repairReportDTO.getCompleteRemark());
            builderRepairReportDTO.setRepairStatus(BuilderRepairReportRepairStatusEnum.COMPLETE);
            return venueManageBuilderRepairReportService.completeRepairReport(builderRepairReportDTO);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWorkOrderStatus(String repairReportNumber, ServiceOrderWorkOrderStatusEnum workOrderStatusEnum) {
        log.info("updateWorkOrderStatus - 更新报修的工单状态, repairReportNumber={}, workOrderStatusEnum={}", repairReportNumber, workOrderStatusEnum);
        // 更新报修记录的派工状态
        RepairReport repairReport = getByReportRepairNumber(repairReportNumber);
        if (repairReport == null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_NOT_EXIST);
        }
        // 工单完成或者作废，报修单都是结束
        repairReport.setWorkOrderStatus(workOrderStatusEnum.getCode());
        if (ServiceOrderWorkOrderStatusEnum.COMPLETE.eq(workOrderStatusEnum) || ServiceOrderWorkOrderStatusEnum.CANCEL.eq(workOrderStatusEnum)) {
            repairReport.setRepairStatus(RepairReportRepairStatusEnum.COMPLETE);
        }
        return updateById(repairReport);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateIsBookService(String repairReportNumber, Integer isBookService) {
        log.info("updateIsBookService - 更新是否预定了服务, repairReportNumber={}, isServiceBook={}", repairReportNumber, isBookService);
        RepairReport repairReport = getByReportRepairNumber(repairReportNumber);
        if (repairReport == null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPAIR_REPORT_NOT_EXIST);
        }
        repairReport.setIsBookService(isBookService);
        if (isBookService == BusinessConstant.YES) {
            repairReport.setIsNeedCompensate(BusinessConstant.YES);
        } else {
            repairReport.setIsNeedCompensate(BusinessConstant.NO);
        }
        return updateById(repairReport);
    }

    @Override
    public boolean sendReportInnerMsg(RepairReport repairReport) {
        log.info("sendReportInnerMsg - 发送报修申请的站内信, repairReport={}", repairReport);
        String content = String.format(BusinessInnerMsgTemplate.REPAIR_REPORT_SUBMIT_TEMPLATE,
                repairReport.getExhibitionManageName(), repairReport.getRepairReportNumber(), repairReport.getCompanyName());
        sendMsgUtil.sendInnerMsg(content, StaticContextUtil.getProjectSystemScene());
        return true;
    }

    @Override
    public void asyncSendReportInnerMsg(RepairReport repairReport) {
        log.info("asyncSendReportInnerMsg - 异步发送报修申请的站内信, repairReport={}", repairReport);
        threadPoolTaskExecutor.execute(() -> sendReportInnerMsg(repairReport));
    }

    /**
     * 生成RepairReport的查询参数.
     *
     * @param model the model
     * @return the query wrapper
     */
    private QueryWrapper<RepairReport> createRepairReportQueryWrapper(RepairReportDTO model) {
        QueryWrapper<RepairReport> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(RepairReport::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(model.getExhibitionManageId() != null, RepairReport::getExhibitionManageId, model.getExhibitionManageId())
                .eq(model.getCompanyId() != null, RepairReport::getCompanyId, model.getCompanyId())
                .eq(StrUtil.isNotBlank(model.getCompanyCode()), RepairReport::getCompanyCode, model.getCompanyCode())
                .like(StrUtil.isNotBlank(model.getCompanyName()), RepairReport::getCompanyName, model.getCompanyName())
                .like(StrUtil.isNotBlank(model.getRepairReportNumber()), RepairReport::getRepairReportNumber, model.getRepairReportNumber())
                .like(StrUtil.isNotBlank(model.getOrderNumber()), RepairReport::getOrderNumber, model.getOrderNumber())
                .like(StrUtil.isNotBlank(model.getSpaceName()), RepairReport::getSpaceName, model.getSpaceName())
                .like(StrUtil.isNotBlank(model.getSiteName()), RepairReport::getSiteName, model.getSiteName())
                .eq(model.getRepairStatus() != null, RepairReport::getRepairStatus, model.getRepairStatus())
                .eq(model.getServiceCategoryId() != null, RepairReport::getServiceCategoryId, model.getServiceCategoryId())
                .in(model.getBelongSystemList() != null && !model.getBelongSystemList().isEmpty(),
                        RepairReport::getBelongSystem, model.getBelongSystemList())
                .in(model.getSpaceCodeList() != null && !model.getSpaceCodeList().isEmpty(),
                        RepairReport::getSpaceCode, model.getSpaceCodeList())
                .ne(RepairReport::getRepairStatus, RepairReportRepairStatusEnum.CANCEL)
        ;
        return queryWrapper;
    }

    /**
     * 生成 场馆查询报修申请 的查询参数.
     *
     * @param model the model
     * @return the query wrapper
     */
    private QueryWrapper<RepairReport> createRepairReportVOQueryWrapperForVenue(RepairReportDTO model) {
        QueryWrapper<RepairReport> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("rr.is_deleted", BusinessConstant.DELETE_NO)
                .eq(model.getExhibitionManageId() != null, "rr.exhibition_manage_id", model.getExhibitionManageId())
                .eq(model.getRepairType() != null, "rr.repair_type", model.getRepairType())
                .eq(model.getRepairStatus() != null, "rr.repair_status", model.getRepairStatus())
                .eq(model.getAcceptCompanyId() != null, "wo.accept_company_id", model.getAcceptCompanyId())
                .like(StrUtil.isNotBlank(model.getAcceptCompanyName()), "wo.accept_company_name", model.getAcceptCompanyName())
                .and(StrUtil.isNotBlank(model.getKeyword()), keywordQuery -> keywordQuery
                        .like("rr.repair_report_number", model.getKeyword())
                        .or()
                        .like("rr.company_name", model.getKeyword())
                        .or()
                        .like("rr.contact", model.getKeyword())
                        .or()
                        .like("rr.phone", model.getKeyword())
                        .or()
                        .like("rr.space_name", model.getKeyword())
                        .or()
                        .like("rr.site_name", model.getKeyword()))
                .ne("rr.repair_status", RepairReportRepairStatusEnum.CANCEL.getCode())
        ;
        return queryWrapper;
    }
}
